﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using WeifenLuo.WinFormsUI.Docking;
using System.Xml;
using dbgservlib;

namespace wfdbg
{
    public partial class Form_Main : Form
    {
        [DllImport( "dbgserv.dll" , CharSet = CharSet.Unicode )]
        public static extern int DbgService_QueryInterface ( out IDbgService DbgService );

        public Form_Output m_WOutput;
        public Form_Locals m_WLocals;
        public Form_Command m_WCommand;
        public Form_Stack m_WStack;

        private DeserializeDockContent m_deserializeDockContent;
        private Timer m_timer = null;
        private uint m_ExecStatus = (uint) DEBUG_STATUS.DEBUG_STATUS_NO_CHANGE;

        IDbgService m_pDbgService = null;
        private string m_SymbolFilePath = null;

        public Form_Main ()
        {
            InitializeComponent();
            m_deserializeDockContent = new DeserializeDockContent( GetContentFromPersistString );

            int result = DbgService_QueryInterface( out m_pDbgService );

            if ( m_pDbgService != null )
            {
                DbgSelectMode dbgselect = new DbgSelectMode();
                dbgselect.ShowDialog();
                string dbginitstring = dbgselect.GetInitString();
                uint ProcessId = dbgselect.GetProcessId();

                try
                {
                    if ( dbginitstring != null && dbginitstring.Length > 0 )
                        m_pDbgService.KernelConnect( dbginitstring );
                    else if ( ProcessId != 0 )
                        m_pDbgService.AttachProcess( ProcessId );
                }
                catch ( Exception exc )
                {
                    MessageBox.Show( exc.ToString() );
                }

                m_WOutput = new Form_Output( m_pDbgService );
                m_WLocals = new Form_Locals( m_pDbgService );
                m_WCommand = new Form_Command( m_pDbgService );
                m_WStack = new Form_Stack( m_pDbgService );
            }

            m_timer = new Timer();
            m_timer.Tick += new EventHandler( TimerProcessing );
            m_timer.Interval = 100;
            m_timer.Enabled = true;
        }

        private void TimerProcessing ( object sender , EventArgs e )
        {
            if ( m_pDbgService == null )
                return;

            uint ExecStatus = 0;
            try
            {
                m_pDbgService.GetExecutionStatus( out ExecStatus );
            }
            catch ( System.Runtime.InteropServices.COMException/* e*/)
            {
                m_DbgStatus.Text = "<unknown>";
                return;
            }

            if ( m_ExecStatus == ExecStatus )
                return;

            uint oldStatus = m_ExecStatus;
            m_ExecStatus = ExecStatus;

            toolStripButton_Go.Enabled = false;
            toolStripButton_Break.Enabled = false;
            m_WCommand.EnterEnable( false );

            switch ( ExecStatus )
            {
                case (uint) DEBUG_STATUS.DEBUG_STATUS_BREAK:
                    m_DbgStatus.Text = "break";
                    if ( oldStatus == (uint) DEBUG_STATUS.DEBUG_STATUS_GO )
                        UpdateCurrentPosition();

                    m_WCommand.EnterEnable( true );
                    m_WStack.RefreshStack();
                    toolStripButton_Go.Enabled = true;
                    
                    break;

                case (uint) DEBUG_STATUS.DEBUG_STATUS_GO:
                    m_DbgStatus.Text = "go";
                    toolStripButton_Break.Enabled = true;
                    break;

                case (uint) DEBUG_STATUS.DEBUG_STATUS_NO_DEBUGGEE:
                    m_DbgStatus.Text = "no debugee";
                    toolStripButton_Break.Enabled = true;
                    break;

                default:
                    m_DbgStatus.Text = ExecStatus.ToString();
                    break;
            }

            m_DbgStatus.Text += ">";
        }

        private static bool MoveToNextElement ( XmlTextReader xmlIn )
        {
            if ( !xmlIn.Read() )
                return false;

            while ( xmlIn.NodeType == XmlNodeType.EndElement )
            {
                if ( !xmlIn.Read() )
                    return false;
            }

            return true;
        }

        private void SaveWfdbConfig ( string configFile )
        {
            try
            {
                configFile += ".dbg";
                FileStream fs = new FileStream( configFile , FileMode.Create , FileAccess.Write );
                XmlTextWriter xmlOut = new XmlTextWriter( fs , Encoding.Unicode );
                xmlOut.Formatting = Formatting.Indented;
                xmlOut.WriteStartDocument();
                xmlOut.WriteStartElement( "WfdbgConfig" );
                if ( m_SymbolFilePath != null )
                {
                    xmlOut.WriteStartElement( "SymbolFilePath" );
                    xmlOut.WriteAttributeString( "Location" , m_SymbolFilePath );
                    xmlOut.WriteEndElement();
                }
                xmlOut.WriteEndElement();
                xmlOut.Flush();
                xmlOut.Close();
            }
            catch ( Exception /*exc*/)
            {
                File.Delete( configFile );
            }
        }

        private void LoadWfdbConfig ( string configFile )
        {
            configFile += ".dbg";
            try
            {
                FileStream fs = new FileStream( configFile , FileMode.Open , FileAccess.Read );

                XmlTextReader xmlIn = new XmlTextReader( fs );
                xmlIn.WhitespaceHandling = WhitespaceHandling.None;

                xmlIn.Read();

                while ( !xmlIn.Name.Equals( "WfdbgConfig" ) )
                {
                    if ( !MoveToNextElement( xmlIn ) )
                        throw new ArgumentException( "wfdbg config not found" );

                    MoveToNextElement( xmlIn );
                    if ( xmlIn.Name.Equals( "SymbolFilePath" ) )
                    {
                        m_SymbolFilePath = xmlIn.GetAttribute( "Location" );
                        ReloadSymbols();
                    }
                }

                xmlIn.Close();
            }
            catch ( Exception /*exc*/)
            {
            }
        }

        private void Form_Main_Load ( object sender , EventArgs e )
        {
            string configFile = Path.Combine( Path.GetDirectoryName( Application.ExecutablePath ) , "wfdbg.cfg" );

            if ( File.Exists( configFile ) )
            {
                dockPanel.LoadFromXml( configFile , m_deserializeDockContent );
                LoadWfdbConfig( configFile );
                UpdateWindowsCheckedStatus();
            }
        }

        private void Form_Main_FormClosing ( object sender , FormClosingEventArgs e )
        {
            /*
            string configFile = Path.Combine( Path.GetDirectoryName( Application.ExecutablePath ) , "wfdbg.cfg" );
            dockPanel.SaveAsXml( configFile );

            SaveWfdbConfig( configFile );*/
            /*else if (File.Exists(configFile))
                File.Delete(configFile);*/
        }

        private IDockContent GetContentFromPersistString ( string persistString )
        {
            if ( persistString == typeof( Form_Output ).ToString() )
                return m_WOutput;
            else if ( persistString == typeof( Form_Locals ).ToString() )
                return m_WLocals;
            else if ( persistString == typeof( Form_Command ).ToString() )
                return m_WCommand;
            else if ( persistString == typeof( Form_Stack ).ToString() )
                return m_WStack;

            return null;
        }

        private void statusStrip_ItemClicked ( object sender , ToolStripItemClickedEventArgs e )
        {
        }

        private void Form_Main_FormClosed ( object sender , FormClosedEventArgs e )
        {
        }

        private void toolStripButtonBreak_Click ( object sender , EventArgs e )
        {
            m_pDbgService.Break();
        }

        private void UpdateWindowsCheckedStatus ()
        {
            if ( m_WCommand.IsHidden )
                commandsToolStripMenuItem.Checked = false;
            else
                commandsToolStripMenuItem.Checked = true;

            if ( m_WOutput.IsHidden )
                outputToolStripMenuItem.Checked = false;
            else
                outputToolStripMenuItem.Checked = true;

            if ( m_WLocals.IsHidden )
                localsToolStripMenuItem.Checked = false;
            else
                localsToolStripMenuItem.Checked = true;

            if ( m_WStack.IsHidden )
                stackToolStripMenuItem.Checked = false;
            else
                stackToolStripMenuItem.Checked = true;
        }

        private void toolStripButtonCls_Click ( object sender , EventArgs e )
        {
            m_WOutput.rtbOutput.ResetText();
        }

        private void commandsToolStripMenuItem_Click ( object sender , EventArgs e )
        {
            if ( m_WCommand.IsHidden )
                m_WCommand.Show( dockPanel );
            else
                m_WCommand.Hide();

            UpdateWindowsCheckedStatus();
        }

        private void outputToolStripMenuItem_Click ( object sender , EventArgs e )
        {
            if ( m_WOutput.IsHidden )
                m_WOutput.Show( dockPanel );
            else
                m_WOutput.Hide();

            UpdateWindowsCheckedStatus();
        }

        private void stackToolStripMenuItem_Click ( object sender , EventArgs e )
        {
            if ( m_WStack.IsHidden )
                m_WStack.Show( dockPanel );
            else
                m_WStack.Hide();

            UpdateWindowsCheckedStatus();
        }

        private void localsToolStripMenuItem_Click ( object sender , EventArgs e )
        {
            if ( m_WLocals.IsHidden )
                m_WLocals.Show( dockPanel );
            else
                m_WLocals.Hide();

            UpdateWindowsCheckedStatus();
        }

        private void saveToolStripMenuItem_Click ( object sender , EventArgs e )
        {
            string configFile = Path.Combine( Path.GetDirectoryName( Application.ExecutablePath ) , "wfdbg.cfg" );
            dockPanel.SaveAsXml( configFile );

            SaveWfdbConfig( configFile );
        }

        private void loadToolStripMenuItem_Click ( object sender , EventArgs e )
        {
            dockPanel.SuspendLayout( true );

            m_WOutput.DockPanel = null;
            m_WLocals.DockPanel = null;
            m_WCommand.DockPanel = null;
            m_WStack.DockPanel = null;

            string configFile = Path.Combine( Path.GetDirectoryName( Application.ExecutablePath ) , "wfdbg.cfg" );

            if ( File.Exists( configFile ) )
            {
                dockPanel.LoadFromXml( configFile , m_deserializeDockContent );
                LoadWfdbConfig( configFile );
            }

            UpdateWindowsCheckedStatus();
            dockPanel.ResumeLayout( true , true );
        }

        private void toolStripButton_Go_Click ( object sender , EventArgs e )
        {
            try
            {
                m_pDbgService.Execute( "g" );
            }
            catch ( Exception /* exc*/)
            {
            }
        }

        private void symbolsFilePathToolStripMenuItem_Click ( object sender , EventArgs e )
        {
            Form_SymbolFilePath W_FSymbolFilePath = new Form_SymbolFilePath( m_SymbolFilePath );
            DialogResult dRes = W_FSymbolFilePath.ShowDialog();
            if ( dRes == DialogResult.OK )
            {
                //if ( m_SymbolFilePath == null || !m_SymbolFilePath.Equals( W_FSymbolFilePath.m_SymbolFilePath ) )
                {
                    m_SymbolFilePath = W_FSymbolFilePath.m_SymbolFilePath;
                    ReloadSymbols();
                }
            }
        }

        private void ReloadSymbols ()
        {
            if ( m_SymbolFilePath == null )
                return;

            try
            {
                m_pDbgService.SetSymbolPath( m_SymbolFilePath );
            }
            catch ( Exception /* exc*/)
            {
            }
        }

        private void UpdateCurrentPosition ()
        {
            ulong Pid = 0;
            ulong Tid = 0;
            try
            {
                m_pDbgService.GetCurrentProcessId( out Pid );
                m_pDbgService.GetCurrentThreadId( out Tid );

                toolStripDropDownButton_Process.Text = "Process " + Pid.ToString() + " (0x" + Pid.ToString("x") + ")";
                toolStripDropDownButton_Thread.Text = "Thread " + Tid.ToString() + " (0x" + Tid.ToString( "x" ) + ")";
            }
            catch ( Exception)
            {
            }
        }

        private void toolStripStatusLabel_Process_Click ( object sender , EventArgs e )
        {

        }
    }
}
